package com.bocloud.cmp.service.resource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bocloud.cmp.common.cache.DictionaryCache;
import com.bocloud.cmp.dao.AlarmDao;
import com.bocloud.cmp.dao.BeanDetailDao;
import com.bocloud.cmp.dao.NetworkDeviceDao;
import com.bocloud.cmp.dao.RackDao;
import com.bocloud.cmp.dao.ServerDao;
import com.bocloud.cmp.dao.StorageDeviceDao;
import com.bocloud.cmp.entity.resource.Alarm;
import com.bocloud.cmp.entity.resource.NetworkDevice;
import com.bocloud.cmp.entity.resource.Rack;
import com.bocloud.cmp.entity.resource.Server;
import com.bocloud.cmp.entity.resource.StorageDevice;
import com.bocloud.cmp.interfaces.resource.RackService;
import com.bocloud.cmp.model.RackBean;
import com.bocloud.cmp.model.RackDevice;
import com.bocloud.cmp.service.utils.ParamHelper;
import com.bocloud.common.enums.BaseStatus;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.Sign;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.MapTools;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 机柜抽象Service接口实现类
 * 
 * @author wei wei
 * @version 1.0
 * @since 2016.02.27
 */
@Service("rackService")
public class RackServiceImpl implements RackService {

	private static Logger logger = LoggerFactory.getLogger(RackServiceImpl.class);
	@Autowired
	private RackDao rackDao;
	@Autowired
	private ServerDao serverDao;
	@Autowired
	private BeanDetailDao beanDetailDao;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private NetworkDeviceDao networkDeviceDao;
	@Autowired
	private StorageDeviceDao storageDeviceDao;
	@Autowired
	private AlarmDao alarmDao;

	@Override
	public BsmResult create(Rack rack, Long userId) {
		try {
			rack.setCreaterId(userId);
			rack.setMenderId(userId);
			rack.setStatus(BaseStatus.NORMAL.name());
			rackDao.save(rack);
		} catch (Exception e) {
			logger.error("Create rack fail:", e);
			return new BsmResult(false, "添加失败");
		}
		return new BsmResult(true, rack, "添加成功");
	}

	@Override
	public BsmResult modify(RackBean bean, Long userId) {
		String path = Rack.class.getSimpleName() + "_" + bean.getId();
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}

			Rack rack = this.rackDao.query(bean.getId());
			if (null == rack) {
				logger.warn("Rack does not exist!");
				return new BsmResult(false, "数据不存在");
			}
			BeanUtils.copyProperties(bean, rack);
			rack.setMenderId(userId);
			this.rackDao.update(rack);
			return new BsmResult(true, "修改成功");
		} catch (Exception e) {
			logger.error("Modify rack fail:", e);
			return new BsmResult(false, "修改失败", null, null);
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult remove(Long id, Long userId) {
		String path = Rack.class.getSimpleName() + "_" + id;
		int count = 0;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}

			Rack object = this.rackDao.query(id);
			if (null == object) {
				logger.warn("Rack does not exist!");
				return new BsmResult(false, "数据不存在");
			}

			Map<String, Object> map = new HashMap<String, Object>();
			map.put(Common.RACK, id);
			count = this.serverDao.count(ParamHelper.getParams(map, Sign.EQ));
			if (count > 0) {
				logger.warn("Remove fail：have servers");
				return new BsmResult(false, "删除失败：该机柜下存在主机，无法删除");
			}

			boolean result = this.rackDao.remove(id, userId);
			if (result) {
				return new BsmResult(true, "删除成功");
			}
			logger.info("Rack has been removed");
			return new BsmResult(true, "已被删除");
		} catch (Exception e) {
			logger.error("Remove rack fail:", e);
			return new BsmResult(false, "删除失败", null, null);
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult basic(Long id) {
		Rack rack = null;
		try {
			rack = this.beanDetailDao.getRackBean(id);
			if (null == rack) {
				logger.warn("Rack does not exist!");
				return new BsmResult(false, rack, "该机柜不存在");
			}
			rack.setTypeName(DictionaryCache.readCache(rack.getType()));
			rack.setMaterialName(DictionaryCache.readCache(rack.getMaterial()));
		} catch (Exception e) {
			logger.error("Query rack fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, rack, "查询成功");
	}

	@Override
	public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple) {
		List<Rack> list = null;
		List<SimpleBean> beans = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			total = this.rackDao.count(params);
			if (simple) {
				beans = this.rackDao.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = this.rackDao.list(page, rows, params, sorter);
				List<Rack> racks = new ArrayList<Rack>();
				List<Alarm> alarmList = alarmDao.listAll();
				for (Rack rack : list) {
					int alarmTotal = 0;
					rack.setTypeName(DictionaryCache.readCache(rack.getType()));
					rack.setMaterialName(DictionaryCache.readCache(rack.getMaterial()));
					List<Server> serverList = serverDao.listByRack(rack.getId());
					List<NetworkDevice> networkDeviceList = networkDeviceDao.listByRackId(rack.getId());
					List<StorageDevice> storageDeviceList = storageDeviceDao.listByRackId(rack.getId());
					rack.setServers(serverList.size());
					rack.setNetworks(networkDeviceList.size());
					rack.setStorages(storageDeviceList.size());
					for (Alarm alarm : alarmList) {
						if (alarm.getType().equalsIgnoreCase("server")) {
							for (Server server : serverList) {
								if (server.getName().equalsIgnoreCase(alarm.getTarget())) {
									alarmTotal++;
								}
							}
						}
						if (alarm.getType().equalsIgnoreCase("networkDevice")) {
							for (NetworkDevice networkDevice : networkDeviceList) {
								if (networkDevice.getName().equalsIgnoreCase(alarm.getTarget())) {
									alarmTotal++;
								}
							}
						}
						if (alarm.getType().equalsIgnoreCase("storageDevice")) {
							for (StorageDevice storageDevice : storageDeviceList) {
								if (storageDevice.getName().equalsIgnoreCase(alarm.getTarget())) {
									alarmTotal++;
								}
							}
						}
					}
					rack.setAlarms(alarmTotal);
					racks.add(rack);
				}
				gridBean = GridHelper.getBean(page, rows, total, racks);
			}
			return new BsmResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query rack list fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
	}

	@Override
	public BsmResult listServers(int page, int rows, List<Param> params, Map<String, String> sorter) {
		List<Server> list = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			list = this.serverDao.list(page, rows, params, sorter);
			total = this.serverDao.count(params);
			gridBean = GridHelper.getBean(page, rows, total, list);
		} catch (Exception e) {
			logger.error("Query server of rack list fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, gridBean, "查询成功");
	}

	@Override
	public BsmResult detail(Long id) {
		Rack rack = null;
		try {
			if (id == 0) {
				rack = new Rack();
				rack.setRacks(this.rackDao.count(null));
				rack.setServers(this.serverDao.count(null));
			} else {
				rack = this.beanDetailDao.getRackBean(id);
				if (null == rack) {
					logger.warn("Rack does not exist!");
					return new BsmResult(true, rack, "该机柜不存在");
				}
				rack.setTypeName(DictionaryCache.readCache(rack.getType()));
				rack.setMaterialName(DictionaryCache.readCache(rack.getMaterial()));

				Map<String, Object> map = new HashMap<String, Object>();
				map.put(Common.RACK, id);
				rack.setServers(this.serverDao.count(ParamHelper.getParams(map, Sign.EQ)));
			}
		} catch (Exception e) {
			logger.error("Query rack detail fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, rack, "查询成功");
	}

	@Override
	public BsmResult inRoom(Long id, Long roomId, Long userId) {
		String path = Rack.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			this.rackDao.belongRoom(id, roomId, userId);
			return new BsmResult(true, "添加成功");
		} catch (Exception e) {
			logger.error("Join rack to room fail:", e);
			return new BsmResult(false, "添加失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult outRoom(Long rackId, Long userId) {
		String path = Rack.class.getSimpleName() + "_" + rackId;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}
			this.rackDao.releaseRoom(rackId, userId);
			return new BsmResult(true, "移除成功");
		} catch (Exception e) {
			logger.error("Remove rack from room fail:", e);
			return new BsmResult(false, "移除失败");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult freeRacks() {
		List<Rack> list = null;
		try {
			list = this.rackDao.listFree();
		} catch (Exception e) {
			logger.error("Query free rack list fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, list, "查询成功");
	}

	@Override
	public BsmResult freeRacks(Long roomId) {
		List<Rack> list = null;
		try {
			list = this.rackDao.listFree(roomId);
		} catch (Exception e) {
			logger.error("Query free rack list fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, list, "查询成功");
	}

	@Override
	public BsmResult checkRange(Long id, Integer slotAmount) {
		try {
			Rack rack = this.rackDao.query(id);
			if (null == rack) {
				logger.warn("Rack does not exist!");
				return new BsmResult(false, "该机柜不存在");
			}

			if (slotAmount <= 0) {
				logger.warn("Can not be less than or equal to 0!");
				return new BsmResult(false, "卡槽数量不可小于等于0");
			}

			if (slotAmount >= rack.getSlotAmount()) {
				return new BsmResult(true, "卡槽数量可以变动");
			}

			List<RackDevice> list = this.serverDao.positions(id, Common.ONE);
			if (list.isEmpty()) {
				return new BsmResult(true, "卡槽数量可以变动");
			}

			RackDevice rackDevice = list.get(0);
			int slotStart = rackDevice.getSlotStart();
			int slotNum = rackDevice.getSlotNum();
			if (slotStart > slotAmount) {
				logger.warn("Slot does not meet the conditions!");
				return new BsmResult(false, "当前卡槽数量小于机柜被占用的最大起始数，数量建议值为" + (slotStart + slotNum));
			}

			if ((slotStart + slotNum - 1) > slotAmount) {
				logger.warn("Slot does not meet the conditions!");
				return new BsmResult(false, "当前卡槽数量小于机柜被占用的最大起始数加其所占卡槽数量，数量建议值为" + (slotStart + slotNum));
			}

			return new BsmResult(true, "卡槽数量可以变动");
		} catch (Exception e) {
			logger.error("Check slot range fail:", e);
			return new BsmResult(false, "卡槽数量不可变动");
		}
	}

	@Override
	public BsmResult checkSlot(Long id, Integer slotStart, Integer slotNum, Long serverId) {
		try {
			Rack rack = this.rackDao.query(id);
			if (null == rack) {
				logger.warn("Rack does not exist!");
				return new BsmResult(false, "该机柜不存在");
			}
			if (null != slotStart && null != slotNum) {

			}
			int slotEnd = slotStart + slotNum - 1;
			if (null != serverId) {
				Server server = this.serverDao.query(serverId);
				if (null == server) {
					logger.warn("Server does not exist!");
					return new BsmResult(false, "该设备不存在");
				}
				int oldStart = server.getSlotStart();
				int oldEnd = oldStart + server.getSlotNum() - 1;
				if (slotStart >= oldStart && slotStart < oldEnd && slotEnd > oldStart && slotEnd <= oldEnd) {
					return new BsmResult(true, "可添加服务器");
				}
			}

			if (slotStart < 1 || slotNum < 1 || (slotStart + slotNum - 1) < 1) {
				logger.warn("Slot parameters error!");
				return new BsmResult(false, "卡槽参数错误");
			}

			int amount = rack.getSlotAmount();

			if (slotStart > amount || slotNum > amount || (slotStart + slotNum - 1) > amount) {
				logger.warn("Slot beyond the scope!");
				return new BsmResult(false, "服务器所占的卡槽超出机柜的卡槽范围");
			}

			List<RackDevice> list = this.serverDao.positions(id, Common.ONE);
			if (list.isEmpty()) {
				return new BsmResult(true, "可添加服务器");
			}

			boolean flag = true;

			int start = 0;
			int end = 0;
			for (RackDevice device : list) {
				start = device.getSlotStart();
				end = device.getSlotStart() + device.getSlotNum() - 1;
				if (slotStart >= start && slotStart <= end) {
					flag = false;
					break;
				}

				if (start >= slotStart && start <= slotEnd) {
					flag = false;
					break;
				}

				if (slotEnd >= start && slotEnd <= end) {
					flag = false;
					break;
				}

				if (end >= slotStart && end <= slotEnd) {
					flag = false;
					break;
				}
			}

			if (flag) {
				return new BsmResult(true, "可添加服务器");
			} else {
				logger.warn("Slot parameters error!");
				return new BsmResult(false, "卡槽" + start + "到" + end + "已被占用");
			}

		} catch (Exception e) {
			logger.error("Check slot fail:", e);
			return new BsmResult(false, "不可添加服务器");
		}
	}

	@Override
	public BsmResult freeNodes(Long id) {
		List<Server> list = null;
		try {
			list = this.serverDao.listFreeNode(id, Rack.class);
		} catch (Exception e) {
			logger.error("Query free server list from rack fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, list, "查询成功");
	}

	@Override
	public BsmResult freeManagers(Long id) {
		List<Server> list = null;
		try {
			list = this.serverDao.listFreeManager(id, Rack.class);
		} catch (Exception e) {
			logger.error("Query free server list from rack fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, list, "查询成功");
	}

	@Override
	public BsmResult slots(Long id) {
		try {
			Rack rack = this.rackDao.query(id);
			if (null == rack) {
				logger.warn("Rack does not exist!");
				return new BsmResult(false, "该机柜不存在");
			}

			int amount = rack.getSlotAmount();

			List<RackDevice> devices = this.serverDao.positions(id, Common.ZERO);
			Map<Integer, Boolean> slots = new HashMap<Integer, Boolean>();
			int start = 0;
			int num = 0;
			for (RackDevice device : devices) {
				start = device.getSlotStart();
				num = device.getSlotNum();
				for (int i = 0; i < num; i++) {
					slots.put(start + i, false);
				}
			}

			for (int i = 1; i <= amount; i++) {
				if (slots.containsKey(i)) {
					continue;
				}
				slots.put(i, true);
			}

			List<Integer> keys = new ArrayList<Integer>(slots.keySet());
			Collections.sort(keys);
			Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
			for (Integer key : keys) {
				map.put(key, slots.get(key));
			}
			return new BsmResult(false, map, "查询成功");
		} catch (Exception e) {
			logger.error("Check slot fail:", e);
			return new BsmResult(false, "不可添加服务器");
		}
	}

	@Override
	public List<String> listServersRackIps(Long id) {
		try {
			return serverDao.rackIps(id);
		} catch (Exception e) {
			logger.error("listServersRackIps fail!", e);
			return null;
		}
	}

	@Override
	public List<String> listServersRoomIps(Long id) {
		try {
			return serverDao.roomIps(id);
		} catch (Exception e) {
			logger.error("listServersRoomIps fail!", e);
			return null;
		}
	}

	@Override
	public List<String> listServersDCIps(Long id) {
		try {
			return serverDao.dcIps(id);
		} catch (Exception e) {
			logger.error("listServersRoomIps fail!", e);
			return null;
		}
	}

	@Override
	public BsmResult resources(Long id) {
		Map<String, Object> maps = Maps.newHashMap();
		List<Param> params = Lists.newArrayList();
		try {
			params.add(new Param(MapTools.simpleMap("rackId", id), Sign.EQ));
			List<Server> servers = this.serverDao.list(1, Integer.MAX_VALUE, params, null);
			maps.put("server", servers);
		} catch (Exception e) {
			logger.error("list resource fail!", e);
			return new BsmResult(false, "查询失败");
		}
		return new BsmResult(true, maps, "查询成功");
	}

}
